#include "packet_manager.h"


packet_manager::packet_manager( uint32_t initial_packets ) : total_packets( initial_packets * 2 ), total_free_packets( initial_packets * 2 ),
	total_used_packets( 0 ), total_memory_used( 0 )
{
	hearts = new MemoryPool<heart_beat>( initial_packets );
	auths = new MemoryPool<authenticate>( initial_packets );
	reqs = new MemoryPool<request>( initial_packets );

	total_memory_free = hearts->getFreeMem() + auths->getFreeMem() + reqs->getFreeMem();
	total_memory = total_memory_free;
}

packet_manager::~packet_manager(void)
{
	delete hearts;
	delete auths;
}

packet *packet_manager::parse( unsigned char *buf, uint32_t length )
{
	uint32_t src, dst, type;
	uint64_t up;
	uint64_t down;
	uint64_t maxup;
	uint64_t maxdown;
	uint64_t free_space;
	uint64_t used_space;
	uint64_t connections_in;
	uint64_t connections_out;
	uint64_t max_connections_in;
	uint64_t max_connections_out;
	uint64_t average_latency;
	unsigned char *b = buf;
	packet *ret = 0;

	if( buf == 0 )
		return 0;

	if( length < packet::PACKET_HEADER_SIZE )
		return 0;

	if( MAKE_WORD( buf[0], buf[1] ) != packet::VERSION )
		return 0;

	src = (buf[2] << 24) | ( buf[3] << 16 ) | ( buf[4] << 8 ) | buf[5];
	dst = (buf[6] << 24) | ( buf[7] << 16 ) | ( buf[8] << 8 ) | buf[9];

	type = buf[10];

	switch( type )
	{
		case HeartBeat:
			ret = hearts->create();

			if( ret == 0 )
				break;
			
			b += packet::PACKET_HEADER_SIZE + heart_beat::PACKET_HEARTBEAT_ID_LEN + 1;
			up = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			down = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			maxup = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			maxdown = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			free_space = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			used_space = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			connections_in = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			connections_out = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			max_connections_in = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			max_connections_out = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );
			b += sizeof( uint64_t );
			average_latency = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );

			((heart_beat *)ret)->init( hearts, src, dst, (char *)( buf + packet::PACKET_HEADER_SIZE + 1 ), up, down, maxup, maxdown, free_space, used_space, 
										connections_in, connections_out, max_connections_in, max_connections_out, average_latency );

			break;

		case Authenticate:
			ret = auths->create();

			if( ret == 0 )
				break;

			b += packet::PACKET_HEADER_SIZE + 1;
			up = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );//base
			b += sizeof( uint64_t );
			down = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );//prime
			b += sizeof( uint64_t );
			maxup = ( ntohl( ( *(uint32_t *)b ) ) << 32 ) | ( ntohl( *(uint32_t *)(b + sizeof( uint32_t ) ) ) );//pub_key

			((authenticate *)ret)->init( auths, src, dst, up, down, maxup );

			break;
	}

	total_memory_free = auths->getFreeMem() + hearts->getFreeMem() + reqs->getFreeMem();
	total_memory_used = auths->getUsedMem() + hearts->getUsedMem() + reqs->getUsedMem();
	total_free_packets = auths->getFreePackets() + hearts->getFreePackets() + reqs->getFreePackets();
	total_used_packets = auths->getUsedPackets() + hearts->getUsedPackets() + reqs->getUsedPackets();

	return ret;
}
